﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver.Linq;
using MongoDB.Driver.Builders;
using System.Diagnostics;
using System.IO;

namespace MongoPerfTest
{
    class ImportDSRDW
    {

        class Test
        {
            public string P { get; set; }
            public string S { get; set; }
            public string G { get; set; }
            public string E { get; set; }

        }

        public static void ProjectionTestCollections()
        {
            var client = new MongoClient("mongodb://localhost");
            var server = client.GetServer();

            var mongo = server.GetDatabase("MongoTestPerf");
            var input = mongo.GetCollection("ScoringMatrixInput");


            for (int j = 0; j < 50; j++)
            {
                Console.WriteLine("");
                {
                    var stopWatch = new Stopwatch();
                    stopWatch.Start();
                    var select = input.Find(Query.EQ("MatrixId", Guid.Empty))
                        .SetFields(new string[] { "P", "E", "S", "G" })
                        .SetLimit(10000)
                        .ToList();

                    var k = select.Average(x =>{

                        var m = new MemoryStream();
                        x.WriteTo(m);
                        return m.Length;
                    
                    } ); 

                    stopWatch.Stop();
                    Console.Write("{0}\t{1}\t{2}\t" ,j, stopWatch.Elapsed.TotalMilliseconds, k);
                }


                {
                    var stopWatch = new Stopwatch();
                    stopWatch.Start();


                    var select = input.AsQueryable<ScoringMatrix>().Take(10000).Select(x => new { x.E, x.S, x.G, x.P   }).ToList();

                    //var select = input.Find(Query.EQ("MatrixId", Guid.Empty))
                    //    .SetLimit(10000)
                    //    .SetFields(new string[] { "P", "E", "S", "G" })
                    //    .ToList();


                    //var k = select.Average(x =>
                    //{

                    //    var m = new MemoryStream();
                    //    x.WriteTo(m);
                    //    return m.Length;

                    //}); 


                    stopWatch.Stop();
                    Console.Write("{0}\t",stopWatch.Elapsed.TotalMilliseconds);
                 //   Console.Write("{0}\t", k);
                }



                {
                    var elems =  new List<BsonDocument>();
                                     
                    var matrix = new BsonDocument("MatrixId", Guid.Empty);
                    var match = new BsonDocument("$match", matrix);
                    elems.Add(match);


                    elems.Add(BsonDocument.Parse("  { $limit:10000} "));
                    elems.Add(BsonDocument.Parse("  { $project: { _id: '$id', P: '$P', S: '$S', G: '$G', E: '$E'}} "));

                    var args = new AggregateArgs(){ Pipeline = elems};
                    var stopWatch = new Stopwatch();
                    stopWatch.Start();
                    var select = input.Aggregate(args).ToList();

                    var k = select.Average(x =>
                    {

                        var m = new MemoryStream();
                        x.WriteTo(m);
                        return m.Length;

                    }); 

                    stopWatch.Stop();
                    Console.Write("{0}\t",stopWatch.Elapsed.TotalMilliseconds);
                    Console.Write("{0}\t", k);
                }


                {
                    var stopWatch = new Stopwatch();
                    stopWatch.Start();
                    var select = input.Find(Query.EQ("MatrixId", Guid.Empty))
                      //  .SetFields(new string[] { "P", "E", "S", "G" })
                        .SetLimit(10000)
                        .ToList();


                    var k = select.Average(x =>
                    {

                        var m = new MemoryStream();
                        x.WriteTo(m);
                        return m.Length;

                    }); 
                    stopWatch.Stop();
                    Console.Write("{1}\t{0}\t", k, stopWatch.Elapsed.TotalMilliseconds);

                }
            }


        }



        public static void SplitIntoMatrixCollections()
        {
            var client = new MongoClient("mongodb://localhost");
            var server = client.GetServer();

            var mongo = server.GetDatabase("MongoTestPerf");

            var input = mongo.GetCollection("ScoringMatrixInput");

            var matrixIds = input.Distinct("MatrixId");

            foreach (var m in matrixIds)
            {
                var id = (Guid)m;

                var coll = mongo.GetCollection("MatrixId_" + id.ToString());
                var docs = input.Find(Query.EQ("MatrixId", id));
                coll.InsertBatch(docs);
            }
        }


        public static void ImportDSRDWToMongoTestPerf()
        {
            var client = new MongoClient("mongodb://localhost");
            var server = client.GetServer();

            var mongo = server.GetDatabase("MongoTestPerf");
            mongo.DropCollection("ImportDSRDW");
           


            using (var db2 = new DSRDWEntities())
            {

                var  allcompanies  =  (from  c in db2.Companies 
                                  join s in db2.Sectors on c.PeerGroupSectorId equals s.SectorId
                                  select new //ScoringMatrix()
                                  {
                                      Id = Guid.NewGuid(),
                                      CompanyId  = c.CompanyId,
                                      PeerGroupId = c.PeerGroupSectorId,
                                      WorkingVersion = c.IndicatorVersion,
                                      PeerGroupName = s.Name, 
                                      ParentGroupId = s.RootSectorId,
                                      CompanyName = c.Name,
                                  } ) ;



                Parallel.ForEach(allcompanies, new ParallelOptions() { MaxDegreeOfParallelism  = 9}, (c) =>
                //foreach(var c in allcompanies)
                {
                    var collection = mongo.GetCollection<ScoringMatrix>("ImportDSRDW");
                    using (var db = new DSRDWEntities())
                    {

                        var matrixes1 = from ci in db.CompanyIndicators
                                        join iw in db.IndicatorWeights on ci.IndicatorId equals iw.IndicatorTemplateId
                                        where ci.CompanyId == c.CompanyId
                                        select iw.MatrixId;

                        var matrixes2 = from ci in db.CompanyIndicators
                                        join tw in db.TopicWeights on ci.IndicatorTopicId equals tw.TopicId
                                        where ci.CompanyId == c.CompanyId
                                        select tw.MatrixId;

                        var matrixes3 = from ci in db.CompanyIndicators
                                        join thw in db.ThemeWeights on ci.IndicatorThemeId equals thw.ThemeId
                                        where ci.CompanyId == c.CompanyId
                                        select thw.MatrixId;

                        var matrixes = matrixes1.Union(matrixes2).Union(matrixes3).Distinct().ToList();


                        foreach (var m in matrixes)
                        {
                            var cm = new ScoringMatrix()
                                        {
                                            CompanyId = c.CompanyId,
                                            PeerGroupId = c.PeerGroupId,
                                            WorkingVersion = c.WorkingVersion,
                                            PeerGroupName = c.PeerGroupName,
                                            ParentGroupId = c.ParentGroupId,
                                            CompanyName = c.CompanyName,
                                            MatrixId = m
                                        };

                            var inds = (from ci in db.CompanyIndicators
                                        join iw in db.IndicatorWeights on ci.IndicatorTemplateId equals iw.IndicatorTemplateId
                                        where ci.CompanyId == cm.CompanyId && iw.MatrixId == m && ci.SectorId == iw.SectorId //&& ci.IndicatorTopicName != "Products"
                                        select new { name = ci.IndicatorNumber, w = iw.IndicatorWeight1, wr = iw.RelativeWeight, d = ci.IndicatorName, s = ci.IndicatorScore }
                                                  ).Distinct().ToList();

                            if (inds.Count > 0)
                            {
                                inds.ForEach(th => cm.SetIndicatorValues(th.name, th.s, th.w, th.wr, th.d));

                                var themes = (from ci in db.CompanyIndicators
                                              // join iw in db.IndicatorWeights on ci.IndicatorId equals iw.IndicatorTemplateId
                                              // join tw in db.TopicWeights on ci.IndicatorTopicId equals tw.TopicId
                                              join thw in db.ThemeWeights on ci.IndicatorThemeId equals thw.ThemeId
                                              where ci.CompanyId == cm.CompanyId && thw.MatrixId == m && ci.SectorId == thw.SectorId
                                              select new { name = ci.IndicatorThemeName, w = thw.ThemeWeight1, wr = thw.RelativeWeight, d = ci.IndicatorThemeName }
                                                 ).Distinct().ToList();
                                themes.ForEach(th => cm.SetIndicatorValues(th.name[0].ToString(), null, th.w, th.wr, th.d));



                                var topics = (from ci in db.CompanyIndicators
                                              // join iw in db.IndicatorWeights on ci.IndicatorId equals iw.IndicatorTemplateId
                                              join tw in db.TopicWeights on ci.IndicatorTopicId equals tw.TopicId
                                              where ci.CompanyId == cm.CompanyId && tw.MatrixId == m && ci.SectorId == tw.SectorId && ci.IndicatorTopicName != "Products"
                                              select new { name = ci.IndicatorNumber.Substring(0, 3), w = tw.TopicWeight1, wr = tw.RelativeWeight, d = ci.IndicatorTopicName }
                                                      ).Distinct().ToList();
                                topics.ForEach(th => cm.SetIndicatorValues(th.name, null, th.w, th.wr, th.d));


                                collection.Insert(cm);


                            }


                        }
                        Console.WriteLine("Added: {0} ({1}) ", c.CompanyName, c.CompanyId);
                    }
                });
            }
        }



    }
}


//// get matrixes 
//var matrixes =  ( from ci in db.CompanyIndicators 
//                    join iw in db.IndicatorWeights on ci.IndicatorId equals iw.IndicatorTemplateId
//                    join tw in db.TopicWeights on ci.IndicatorTopicId equals tw.TopicId
//                    join thw in db.ThemeWeights on ci.IndicatorThemeId equals thw.ThemeId
//                    where  ci.CompanyId == c.CompanyId
//                    select new {
//                                c =ci ,
//                                sid=iw.SectorId, 
//                                mid=iw.MatrixId, 
//                                iw  = iw.IndicatorWeight1, 
//                                iwr = iw.RelativeWeight, 
//                                sid2 = tw.SectorId, 
//                                mid2 = tw.MatrixId, 
//                                tiw  = tw.TopicWeight1, 
//                                tiwr = tw.RelativeWeight, 
//                                sid3 = thw.SectorId, 
//                                mid3 = thw.MatrixId, 
//                                thw = thw.ThemeWeight1, 
//                                thwr = thw.RelativeWeight, 
//                    }).ToList();

